package com.googlecode.yoohoo.xmppcore.protocol.parsing.error;

import java.util.List;

import com.googlecode.yoohoo.xmppcore.protocol.IError;
import com.googlecode.yoohoo.xmppcore.protocol.XmlLangText;
import com.googlecode.yoohoo.xmppcore.protocol.XmppProtocolException;
import com.googlecode.yoohoo.xmppcore.protocol.parsing.Attribute;
import com.googlecode.yoohoo.xmppcore.protocol.parsing.IXmppParser;
import com.googlecode.yoohoo.xmppcore.protocol.parsing.ProtocolKey;
import com.googlecode.yoohoo.xmppcore.protocol.stanza.error.BadRequest;
import com.googlecode.yoohoo.xmppcore.protocol.stanza.error.ErrorType;
import com.googlecode.yoohoo.xmppcore.protocol.stanza.error.StanzaError;
import com.googlecode.yoohoo.xmppcore.protocol.stream.error.StreamError;

public class ErrorParser implements IXmppParser<IError> {
	private XmppErrorType type;
	private IError error;
	
	public ErrorParser(XmppErrorType type) {
		this.type = type;
	}
	
	@Override
	public IError getObject() {
		return error;
	}

	@Override
	public void processAttributes(String path, List<Attribute> attributes) {
		if ("error".equals(path)) {
			if (XmppErrorType.STREAM == type) {
				error = new StreamError();
			} else {
				error = new StanzaError();
				if (attributes.size() != 1) {
					throw new XmppProtocolException(new BadRequest("Element 'error' must has and only has an attribute 'error-type'."));
				}
				
				Attribute attribute = attributes.get(0);
				if (attribute.getPrefix() != null || "error-type".equals(attribute.getLocalName())) {
					throw new XmppProtocolException(new BadRequest("Element 'error' must has an attribute 'error-type'."));
				}
				
				for (ErrorType errorType : ErrorType.values()) {
					if (errorType.toString().equals(attribute.getValue())) {
						((StanzaError)error).setErrorType(errorType);
						
						return;
					}
				}
				
				throw new XmppProtocolException(new BadRequest(String.format(
					"Invalid value[%s] for attribute 'error-type'.", attribute.getValue())));
			}
		} else {
			throw new XmppProtocolException(new BadRequest(String.format(
				"XML parsing error. Invalid element '%s'.", path)));
		}
	}

	@Override
	public void processEmbeddedObject(ProtocolKey protocolKey, Object object) {
		if (StreamError.NAMESPACE_STREAM_ERROR.equals(protocolKey.getNamespace()) ||
				StanzaError.NAMESPACE_STANZA_ERROR.equals(protocolKey.getNamespace())) {
			if ("text".equals(protocolKey.getLocalName())) {
				if (error.getText() != null) {
					throw new XmppProtocolException(new BadRequest("Reduplicated element 'text'."));
				}
				
				if (object instanceof XmlLangText) {
					error.setText((XmlLangText)object);
				}
			} else {
				if (error.getDefinedCondition() != null) {
					throw new XmppProtocolException(new BadRequest("Reduplicated element 'defined-condition'."));
				}
				
				error.setDefinedCondition((String)object);
			}
		} else {
			if (error.getApplicationSpecificCondition() != null) {
				throw new XmppProtocolException(new BadRequest("Reduplicated element 'application-specific-condition'."));
			}
			
			error.setApplicationSpecificCondition(object);
		}
	}

	@Override
	public void processText(String path, String text) {
		if (text != null)
			throw new XmppProtocolException(new BadRequest("Element 'error' doesn't allow containing text"));
	}

}
